﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Net.Sockets;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Threading;

namespace Galaxy_Wars
{
    class Game
    {
        GameGui form;
        NetworkClient client;
        List<Planet> planets = new List<Planet>();
        List<Fleet> fleets = new List<Fleet>();
        Random random = new Random();
        int dayProduction;
        int amountofplanets;
        int playerid;
        private Boolean turnended = false;

        public Game(GameGui form)
        {
            this.playerid = Convert.ToInt32(form.playerID);
            this.dayProduction = form.dayProduction;
            this.amountofplanets = form.amountofplanets;
            this.form = form;

            string[] alleNamen = File.ReadAllLines("planetnames.txt");
            Random random = new Random();

            for (int i = 0; i < amountofplanets; i++)
            {
                newPlanet(i, i, alleNamen[random.Next(0, alleNamen.Length - 1)]);
            }
            client = new NetworkClient("");
            handleLogin();
            Thread thread = new Thread(gameHandeler);
            thread.Start();
        }

        public void gameHandeler()
        {
            Console.WriteLine("thread started");
            string s = client.ReadMessage();
            if(s.Substring(0,4).Equals("?TURN")){
                //if my turn then do things and send
                if (s.Substring(5, s.Length).Equals(playerid.ToString()))
                {
                    Console.WriteLine("My turn");
                    //enable form
                    form.Enabled = true;
                    //while(!turnended){}
                }
                //if not my turn then wait and disable the form
                else 
                {
                     //disable form
                    form.Enabled = false;
                }
            }
        }

        /// <summary>
        /// Handle the login procedure with the GALAXY WARS SERVER
        /// </summary>

        public void handleLogin() {
            Boolean done = false;
            while (!done)
            {
                object received = client.ReadMessage();
                //Console.WriteLine("Received: {0}", received.ToString());
                string receivedString = received as string;

                if (receivedString == "?ID")
                {
                    client.SendMessage(form.playername);

                    //SendMessage(client, "exitgame");
                }
                else if (receivedString.Substring(0, 5) == "?IDNR")
                {
                    playerid = Convert.ToInt32(receivedString.Substring(5, 1));
                    Console.WriteLine("PlayerID = " + playerid);
                    form.playerID = playerid.ToString();
                    client.SendMessage(playerid.ToString());
                }
                else if (receivedString == "?TYPE")
                {
                    client.SendMessage("!" + form.gameType.ToUpper());
                }
                else if (receivedString == "?GAME")
                {
                    Console.WriteLine("Command ?GAME");
                    Console.WriteLine("Host: {0}<Hostup: {1}>",form.gameType,form.gameType.ToUpper());
                    if (form.gameType.ToUpper().Equals("HOST"))
                    {
                        //client.sendObject(new SendObj(getAllPlanets(), getAllFleets()));
                        client.SendObjecttoByte(new SendObj(getAllPlanets(),getAllFleets()));
                        Console.WriteLine("Sending to server complete");
                    }
                    else 
                    { 
                        SendObj sendobject = client.ReceiveObjectfromByte() as SendObj;
                        Console.WriteLine("Loaded SendObj with planetarr size: " + sendobject.getListPlanet().Count);
                        planets = sendobject.getListPlanet();
                        fleets = sendobject.getListFleet();
                        renewOverview();
                        
                    }
                    done = true;
                }
                else
                {
                    done = received.Equals("exitgame");
                }
            }
            Console.WriteLine("Done authenticating to THE SERVER!!!!");
        }

        

        public void formClosingGoodbye()
        {
            //if (client != null)
            try
            {
                if (client.client != null && client.client.Connected)
                {
                    client.SendMessage("exitgame");
                }
            }
            catch (Exception) { }
        }

        /// <summary>
        /// Method for creating a new Planet. Method ensures unique coordinates for the planet
        /// by calling checkCoords(). When the coordinates return unique a new planet is created
        /// with these coordinates and the planet get added to List<Planet> planets.
        /// </summary>
        /// <param name="strName"></param>
        private void newPlanet(int newplanetnumber, int playerNumber, string planetName)
        {
            Rectangle rect = new Rectangle(random.Next(form.canvas.Width - 50), random.Next(form.canvas.Height - 50), 25, 25);
            foreach (Planet p in planets)
            {
                if (p.getCoords().IntersectsWith(rect))
                {
                    rect = checkCoords();
                }
            }
            Planet TmpPlanet = new Planet(newplanetnumber, playerNumber, planetName, rect, dayProduction);

            planets.Add(TmpPlanet);
            form.drawPlanet(TmpPlanet);
        }

        /// <summary>
        /// Recursive method only to be used by newPlanet().
        /// This method keeps calling itself until proper coordinates are found for a new planet.
        /// NOTE: if this method is needed apart from initializing a new planet, YOU ARE DOING A HELL LOTTA WRONG!
        /// </summary>
        /// <returns></returns>
        private Rectangle checkCoords()
        {
            Rectangle rect = new Rectangle(random.Next(form.canvas.Width - 50), random.Next(form.canvas.Height - 50), 25, 25);

            foreach (Planet p in planets)
            {
                if (p.getCoords().IntersectsWith(rect))
                {
                    rect = checkCoords();
                }
            }
            return rect;
        }

        /// <summary>
        /// This method ensures that the canvas is cleaned and after this all planets get redrawn.
        /// </summary>
        private void renewOverview()
        {
            form.resetCanvas();

            foreach (Planet p in planets)
            {
                form.drawPlanet(p);
            }
        }

        /// <summary>
        /// should only be called by Form1.Form1_MouseClick().
        /// This method is accountable for all method calls, etc. after the Playing field is clicked in Form1.
        /// </summary>
        /// <param name="e"></param>
        public void playingFieldClicked(System.Windows.Forms.MouseEventArgs e)
        {
            //Console.WriteLine("chosen planet = " + form.chosenPlanet.getName() + " actionplanet = " + form.actionPlanet.getName());

            renewOverview();
            foreach (Planet p in planets)
            {
                if (p.getCoords().Contains(e.Location))
                {
                    Console.WriteLine("You clicked planet : " + p.getName());
                    if (form.actionPlanet == null)
                    {
                        form.drawPlanetData(p);
                    }
                    else 
                    {
                        int travelduration = getTravelDuration(form.actionPlanet, p);

                        Console.WriteLine("attack started");
                        fleets.Add(new Fleet(form.actionPlanet.getPlanetnumber(), p.getPlanetnumber(), travelduration, Convert.ToInt32(form.sendShipsTextbox.Text)));
                        Console.WriteLine("Distance to target is : " + travelduration);
                    }
                    break;
                }
                else 
                {
                    form.chosenPlanet = null;
                    form.showMenuItems(false);
                }
            }
        }


        private int getTravelDuration(Planet startPlanet, Planet endPlanet)
        {
            int deltaX = (endPlanet.getCoords().X - startPlanet.getCoords().X);
            int deltaY = (endPlanet.getCoords().Y - startPlanet.getCoords().Y);
            double distance = Math.Sqrt( deltaX*deltaX + deltaY*deltaY );

            return (int)distance;
        }

        /// <summary>
        /// should only be called by Form1.Form1_MouseClickMenu().
        /// This method is accountable for all method calls, etc. after the Menu is clicked in Form1.
        /// </summary>
        /// <param name="e"></param>
        public void MenubarClicked(System.Windows.Forms.MouseEventArgs e)
        {
            
        }

        public string getPlayerByID(int playerid) 
        {
            return "Jesse";
        }

        public List<Planet> getAllPlanets()
        {
            return planets;
        }

        public List<Fleet> getAllFleets() {
            return fleets;
        }

        public void endTurn()
        {
            //Dec fleet time en als fleetlifetime = 0 dan toevoegen aan dest planeet en delete Fleet
            foreach (Fleet fl in fleets)
            {
                if (fl.distance < 100)
                {
                    Console.WriteLine("yeah man, heavy battle or not if this is your own planet");
                    foreach (Planet p in planets)
                    {
                        if (p.getPlanetnumber() == fl.getDestinationPlanet())
                        {
                            p.receiveShips(fl.getShips());
                            fleets.Remove(fl);
                        }
                    }
                }
                else
                {
                    fl.distance -= 100;
                }
            }
        }



    }
}
